﻿using System;
using System.Xml;
using System.Data;
using System.Collections.ObjectModel;
using SharePointSearchBench.Library;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using System.Net;
using System.Diagnostics;
using Microsoft.Office.Server.Search.Query;

namespace SharePointSearchBench.Tests
{
    /// <summary>
    ///This is a test class for SearchTest and is intended
    ///to contain all SearchTest Unit Tests
    ///</summary>
    [TestClass()]
    public class SearchTest
    {
        public static Search GetTestSearchObject()
        {
            Search target = new Search();
            ISearchBenchContext searchBenchContext = new TestSearchBenchContext(target);
            target.SetSearchBenchContext(searchBenchContext);
            return target;

        }

        /// <summary>
        ///A test for SearchType
        ///</summary>
        [TestMethod()]
        public void SearchTypeTest()
        {
            Search target = SearchTest.GetTestSearchObject();
            SearchType expected = new SearchType();
            SearchType actual;
            target.SearchType = expected;
            actual = target.SearchType;
            Assert.AreEqual(expected, actual);
        }

        /// <summary>
        ///A test for SearchText
        ///</summary>
        [TestMethod()]
        public void SearchTextTest()
        {
            Search target = SearchTest.GetTestSearchObject();
            SearchText expected = new SearchText(Guid.NewGuid().ToString());
            SearchText actual;
            target.SearchText = expected;
            actual = target.SearchText;
            Assert.AreEqual(expected, actual);
        }

        [TestMethod()]
        public void ExecuteObjectModelKeywordSearchTest()
        {
            Search target = SearchTest.GetTestSearchObject();
            target.SearchType = SearchType.Keyword;
            target.SearchText = new SearchText(TestSettings.BaseKeywordQueryText);
            Uri siteUri = new Uri(TestSettings.ServiceUrl);
            target.ContextUri = siteUri;
            target.ApiSource = ApiSource.ObjectModel;

            DataSet results = target.Execute();
            SearchTest.PeekAtResults(results);
        }

        [TestMethod()]
        public void ExecuteObjectModelFullTextSearchTest()
        {
            Search target = SearchTest.GetTestSearchObject();
            target.SearchType = SearchType.FullText;
            target.SearchText = new SearchText(TestSettings.BaseFullTextQueryText);
            Uri siteUri = new Uri(TestSettings.ServiceUrl);
            target.ApiSource = ApiSource.ObjectModel;
            target.ContextUri = siteUri;
            DataSet results = target.Execute();
            SearchTest.PeekAtResults(results);
        }

        /// <summary>
        ///A test for Execute
        ///</summary>
        [TestMethod()]
        public void ExecuteServiceKeywordTestWithCredentials()
        {
            Search target = SearchTest.GetTestSearchObject();
            target.SearchType = SearchType.Keyword;
            NetworkCredential credentials = SearchTest.GetCredentials();
            Uri serviceUri = new Uri(TestSettings.ServiceUrl);
            target.SearchText = new SearchText(TestSettings.BaseKeywordQueryText);
            target.ApiSource = ApiSource.Service;
            target.ContextUri = serviceUri;
            target.Credentials = credentials;
            DataSet results = target.Execute();

            Assert.AreEqual(1, results.Tables.Count);

            SearchTest.PeekAtResults(results);
        }

        [TestMethod()]
        [ExpectedException(typeof(MissingSearchTextException))]
        public void ExecuteFullTextObjectModelSearchWithNoSearchText()
        {
            Search target = SearchTest.GetTestSearchObject();
            target.SearchType = SearchType.FullText;
            target.ApiSource = ApiSource.ObjectModel;
            Uri uri = new Uri(TestSettings.ServiceUrl);
            target.ContextUri = uri;
            DataSet results = target.Execute();
        }

        [TestMethod()]
        [ExpectedException(typeof(MissingSearchTextException))]
        public void ExecuteKeywordObjectModelSearchWithNoSearchText()
        {
            Search target = SearchTest.GetTestSearchObject();
            target.SearchType = SearchType.Keyword;
            target.ApiSource = ApiSource.ObjectModel;
            Uri uri = new Uri(TestSettings.ServiceUrl);
            target.ContextUri = uri;
            DataSet results = target.Execute();
        }

        [TestMethod()]
        [ExpectedException(typeof(MissingSearchTextException))]
        public void ExecuteFullTextServiceSearchWithNoSearchText()
        {
            Search target = SearchTest.GetTestSearchObject();
            target.SearchType = SearchType.FullText;
            target.ApiSource = ApiSource.Service;
            Uri uri = new Uri(TestSettings.ServiceUrl);
            target.ContextUri = uri;
            target.Credentials = SearchTest.GetCredentials();
            DataSet results = target.Execute();
        }

        [TestMethod()]
        [ExpectedException(typeof(MissingSearchTextException))]
        public void ExecuteKeywordServiceSearchWithNoSearchText()
        {
            Search target = SearchTest.GetTestSearchObject();
            target.SearchType = SearchType.Keyword;
            target.ApiSource = ApiSource.Service;
            Uri uri = new Uri(TestSettings.ServiceUrl);
            target.ContextUri = uri;
            target.Credentials = SearchTest.GetCredentials();
            DataSet results = target.Execute();
        }

        /// <summary>
        ///A test for Execute
        ///</summary>
        [TestMethod()]
        [ExpectedException(typeof(MissingCredentialsException))]
        public void ExecuteServiceKeywordTestWithNullCredentials()
        {
            Search target = SearchTest.GetTestSearchObject();
            target.SearchType = SearchType.Keyword;
            target.SearchText = new SearchText(TestSettings.BaseKeywordQueryText);
            Uri serviceUri = new Uri(TestSettings.ServiceUrl);
            target.ContextUri = serviceUri;
            target.ApiSource = ApiSource.Service;
            target.Execute();
        }

        [TestMethod()]
        [ExpectedException(typeof(MissingContextUriException))]
        public void ExecuteServiceKeywordTestWithNullServiceUri()
        {
            Search target = SearchTest.GetTestSearchObject();
            target.SearchType = SearchType.Keyword;
            NetworkCredential credentials = SearchTest.GetCredentials();
            target.SearchText = new SearchText(TestSettings.BaseKeywordQueryText);
            target.ApiSource = ApiSource.Service;
            target.Credentials = credentials;
            target.Execute();
        }

        /// <summary>
        ///A test for Execute
        ///</summary>
        [TestMethod()]
        public void ExecuteServiceFullTextTestWithCredentials()
        {
            Search target = SearchTest.GetTestSearchObject();
            target.SearchType = SearchType.FullText;
            NetworkCredential credentials = SearchTest.GetCredentials();
            Uri serviceUri = new Uri(TestSettings.ServiceUrl);
            target.SearchText = new SearchText(TestSettings.BaseFullTextQueryText);
            target.Credentials = credentials;
            target.ApiSource = ApiSource.Service;
            target.ContextUri = serviceUri;
            DataSet results = target.Execute();

            Assert.AreEqual(1, results.Tables.Count);

            SearchTest.PeekAtResults(results);
        }

        static NetworkCredential GetCredentials()
        {
            NetworkCredential credentials = new NetworkCredential(TestSettings.ServiceUsername, TestSettings.ServicePassword, TestSettings.ServiceDomain);
            return credentials;
        }

        static void PeekAtResults(DataSet results)
        {
            foreach(DataColumn column in results.Tables[0].Columns)
            {
                Debug.Write(column + "\t");
            }
            Debug.Write("\n");

            if(results.Tables[0].Rows.Count > 0)
            {
                int max = 5;
                if(results.Tables[0].Rows.Count < 5)
                {
                    max = results.Tables[0].Rows.Count;
                }
                for(int i = 0;i < max;i++)
                {
                    foreach(DataColumn column in results.Tables[0].Columns)
                    {
                        Debug.Write(results.Tables[0].Rows[i][column] + "\t");
                    }
                    Debug.Write("\n");
                }
            }
        }

        [TestMethod()]
        public void GetPropertiesWithServiceTest()
        {
            Search target = SearchTest.GetTestSearchObject();
            target.ApiSource = ApiSource.Service;
            target.ContextUri = new Uri(TestSettings.ServiceUrl);
            target.Credentials = SearchTest.GetCredentials();
            Collection<SearchProperty> properties = target.SearchProperties;
            Assert.IsTrue(properties.Count > 0);
        }

        [TestMethod()]
        public void GetPropertiesWithObjectModelTest()
        {
            Search target = SearchTest.GetTestSearchObject();
            target.ApiSource = ApiSource.ObjectModel;
            target.ContextUri = new Uri(TestSettings.ServiceUrl);
            Collection<SearchProperty> properties = target.SearchProperties;
            Assert.IsTrue(properties.Count > 0);
        }

        [TestMethod()]
        public void GetScopesWithObjectModelTest()
        {
            Search target = SearchTest.GetTestSearchObject();
            target.ApiSource = ApiSource.ObjectModel;
            target.ContextUri = new Uri(TestSettings.ServiceUrl);
            Collection<SearchScope> items = target.SearchScopes;
            Assert.IsTrue(items.Count > 0);
        }

        [TestMethod()]
        public void GetScopesWithServiceTest()
        {
            Search target = SearchTest.GetTestSearchObject();
            target.ApiSource = ApiSource.Service;
            target.Credentials = SearchTest.GetCredentials();
            target.ContextUri = new Uri(TestSettings.ServiceUrl);
            Collection<SearchScope> items = target.SearchScopes;
            Assert.IsTrue(items.Count > 0);
        }

        [TestMethod()]
        [ExpectedException(typeof(MissingCredentialsException))]
        [Ignore()]
        public void GetPropertiesWithServiceNoCredentialsTest()
        {
            Search target = SearchTest.GetTestSearchObject();
            target.ApiSource = ApiSource.Service;
            target.ContextUri = new Uri(TestSettings.ServiceUrl);
            target.Credentials = null;
            object value = target.SearchProperties;
        }

        [TestMethod()]
        [ExpectedException(typeof(MissingContextUriException))]
        public void GetPropertiesWithServiceNoContextUrlTest()
        {
            Search target = SearchTest.GetTestSearchObject();
            target.ApiSource = ApiSource.Service;
            target.ContextUri = null;
            target.Credentials = SearchTest.GetCredentials();
            object value = target.SearchProperties;
        }

        [TestMethod()]
        [ExpectedException(typeof(MissingContextUriException))]
        public void GetPropertiesWithObjectModelNoContextUrlTest()
        {
            Search target = SearchTest.GetTestSearchObject();
            target.ApiSource = ApiSource.ObjectModel;
            target.ContextUri = null;
            target.Credentials = SearchTest.GetCredentials();
            object value = target.SearchProperties;
        }


        [TestMethod()]
        [ExpectedException(typeof(MissingCredentialsException))]
        [Ignore()]
        public void GetScopesWithServiceNoCredentialsTest()
        {
            Search target = SearchTest.GetTestSearchObject();
            target.ApiSource = ApiSource.Service;
            target.ContextUri = new Uri(TestSettings.ServiceUrl);
            target.Credentials = null;
            object value = target.SearchScopes;
        }

        [TestMethod()]
        [ExpectedException(typeof(MissingContextUriException))]
        public void GetScopesWithServiceNoContextUrlTest()
        {
            Search target = SearchTest.GetTestSearchObject();
            target.ApiSource = ApiSource.Service;
            target.ContextUri = null;
            target.Credentials = SearchTest.GetCredentials();
            object value = target.SearchScopes;
        }

        [TestMethod()]
        [ExpectedException(typeof(MissingContextUriException))]
        public void GetScopesWithObjectModelNoContextUrlTest()
        {
            Search target = SearchTest.GetTestSearchObject();
            target.ApiSource = ApiSource.ObjectModel;
            target.ContextUri = null;
            target.Credentials = SearchTest.GetCredentials();
            object value = target.SearchScopes;
        }

        [TestMethod()]
        [ExpectedException(typeof(ResultTypeNotSupportedException))]
        public void TestPacketGenerationWithNonRelevantResultsWithService()
        {
            Search target = SearchTest.GetTestSearchObject();
            target.ApiSource = ApiSource.Service;
            target.ContextUri = new Uri(TestSettings.ServiceUrl);
            target.Credentials = SearchTest.GetCredentials();
            target.SearchType = SearchType.Keyword;
            target.SearchResultType = SearchResultType.DefinitionResults;

            string xml = target.BuildKeywordQueryPacket();
        
        }


        [TestMethod()]
        public void TestSearchPropertyMembers()
        {
            DataTable table = new DataTable();
            table.Columns.Add(new DataColumn("Name", typeof(string)));
            table.Columns.Add(new DataColumn("Description", typeof(string)));
            table.Columns.Add(new DataColumn("Type", typeof(string)));
            table.Columns.Add(new DataColumn("Retrievable", typeof(bool)));
            table.Columns.Add(new DataColumn("FullTextQueriable", typeof(bool)));

            string name = Guid.NewGuid().ToString();
            string description = Guid.NewGuid().ToString();
            string type = Guid.NewGuid().ToString();
            bool retrievable = false;
            bool fullTextQueriable = true;

            DataRow newRow = table.NewRow();
            newRow["Name"] = name;
            newRow["Description"] = description;
            newRow["Type"] = type;
            newRow["Retrievable"] = retrievable;
            newRow["FullTextQueriable"] = fullTextQueriable;

            SearchProperty property = new SearchProperty(newRow);

            Assert.AreEqual(name, property.Name);
            Assert.AreEqual(description, property.Description);
            Assert.AreEqual(type, property.TypeName);
            Assert.AreEqual(retrievable, property.Retrievable);
            Assert.AreEqual(fullTextQueriable, property.FullTextQueriable);

        }

        [TestMethod()]
        public void TestSearchScopeMembers()
        {
            DataTable table = new DataTable();
            table.Columns.Add(new DataColumn("Name", typeof(string)));

            string name = Guid.NewGuid().ToString();

            DataRow newRow = table.NewRow();
            newRow["Name"] = name;

            SearchScope item = new SearchScope(newRow);

            Assert.AreEqual(name, item.Name);

        }

        [TestMethod()]
        [ExpectedException(typeof(ResultTypeNotSupportedException))]
        public void TestServiceSearchWithDefinitionResults()
        {
            Search target = SearchTest.GetTestSearchObject();
            target.ApiSource = ApiSource.Service;
            target.ContextUri = new Uri(TestSettings.ServiceUrl);
            target.Credentials = SearchTest.GetCredentials();
            target.SearchText = new SearchText(TestSettings.BaseKeywordQueryText);
            target.SearchResultType = SearchResultType.DefinitionResults;
            target.Execute();
        }

        [TestMethod()]
        [ExpectedException(typeof(ResultTypeNotSupportedException))]
        public void TestServiceSearchWithHighConfidenceResults()
        {
            Search target = SearchTest.GetTestSearchObject();
            target.ApiSource = ApiSource.Service;
            target.ContextUri = new Uri(TestSettings.ServiceUrl);
            target.Credentials = SearchTest.GetCredentials();
            target.SearchText = new SearchText(TestSettings.BaseKeywordQueryText);
            target.SearchResultType = SearchResultType.HighConfidence;
            target.Execute();
        }

        [TestMethod()]
        [ExpectedException(typeof(ResultTypeNotSupportedException))]
        public void TestServiceSearchWithSpecialTermResults()
        {
            Search target = SearchTest.GetTestSearchObject();
            target.ApiSource = ApiSource.Service;
            target.ContextUri = new Uri(TestSettings.ServiceUrl);
            target.Credentials = SearchTest.GetCredentials();
            target.SearchText = new SearchText(TestSettings.BaseKeywordQueryText);
            target.SearchResultType = SearchResultType.SpecialTerm;
            target.Execute();
        }

        [TestMethod()]
        public void TestObjectModelSearchWithDefinitionResults()
        {
            Search target = SearchTest.GetTestSearchObject();
            target.ApiSource = ApiSource.ObjectModel;
            target.ContextUri = new Uri(TestSettings.ServiceUrl);
            target.SearchText = new SearchText(TestSettings.BaseKeywordQueryText);
            target.SearchResultType = SearchResultType.DefinitionResults;
            DataSet results = target.Execute();
            Assert.IsTrue(results.Tables.Count > 0);
        }

        [TestMethod()]
        public void TestObjectModelSearchWithHighConfidenceResults()
        {
            Search target = SearchTest.GetTestSearchObject();
            target.ApiSource = ApiSource.ObjectModel;
            target.ContextUri = new Uri(TestSettings.ServiceUrl);
            target.SearchText = new SearchText(TestSettings.BaseKeywordQueryText);
            target.SearchResultType = SearchResultType.HighConfidence;
            DataSet results = target.Execute();
            Assert.IsTrue(results.Tables.Count > 0);
        }

        [TestMethod()]
        public void TestObjectModelSearchWithSpecialTermResults()
        {
            Search target = SearchTest.GetTestSearchObject();
            target.ApiSource = ApiSource.ObjectModel;
            target.ContextUri = new Uri(TestSettings.ServiceUrl);
            target.SearchText = new SearchText(TestSettings.BaseKeywordQueryText);
            target.SearchResultType = SearchResultType.SpecialTerm;
            DataSet results = target.Execute();
            Assert.IsTrue(results.Tables.Count > 0);
        }

        [TestMethod()]
        public void TestObjectModelKeywordDisplayFields()
        {
            Search target = SearchTest.GetTestSearchObject();
            target.ApiSource = ApiSource.ObjectModel;
            target.ContextUri = new Uri(TestSettings.ServiceUrl);
            target.SearchType = SearchType.Keyword;
            target.SearchText = new SearchText(TestSettings.BaseKeywordQueryText);

            foreach(string field in TestSettings.BaseDisplayFields)
            {
                target.DisplayFields.Add(field);
            }

            DataSet results = target.Execute();
            DataTable table = results.Tables[0];
            Assert.AreEqual(target.DisplayFields.Count, table.Columns.Count);

            foreach(string field in target.DisplayFields)
            {
                Assert.IsNotNull(table.Columns[field]);
            }
        }

        [TestMethod()]
        public void TestWebServiceKeywordDisplayFields()
        {
            Search target = SearchTest.GetTestSearchObject();
            target.ApiSource = ApiSource.Service;
            target.ContextUri = new Uri(TestSettings.ServiceUrl);
            target.SearchType = SearchType.Keyword;
            target.SearchText = new SearchText(TestSettings.BaseKeywordQueryText);
            target.Credentials = SearchTest.GetCredentials();

            foreach(string field in TestSettings.BaseDisplayFields)
            {
                target.DisplayFields.Add(field);
            }

            DataSet results = target.Execute();
            DataTable table = results.Tables[0];
            Assert.AreEqual(target.DisplayFields.Count, table.Columns.Count);

            foreach(string field in target.DisplayFields)
            {
                Assert.IsNotNull(table.Columns[field]);
            }
        }

        [TestMethod()]
        public void TestObjectModelKeywordSortFields()
        {
            Search target = SearchTest.GetTestSearchObject();
            target.ApiSource = ApiSource.ObjectModel;
            this.TestKeywordSortFields(target);
        }

        [TestMethod()]
        public void TestServiceKeywordSortFields()
        {
            Search target = SearchTest.GetTestSearchObject();
            target.ApiSource = ApiSource.Service;
            this.TestKeywordSortFields(target);
        }

        void TestKeywordSortFields(Search target)
        {
            target.ContextUri = new Uri(TestSettings.ServiceUrl);
            target.SearchType = SearchType.Keyword;
            target.SearchText = new SearchText(TestSettings.LargeResultsKeywordQueryText);
            target.Credentials = SearchTest.GetCredentials();

            foreach(string field in TestSettings.BaseDisplayFields)
            {
                target.DisplayFields.Add(field);
                target.SortFields.Add(field);
            }

            DataSet results = target.Execute();
            DataTable table = results.Tables[0];

            DataRow row = null;
            DataRow previousRow = null;

            for(int i = 1;i < table.Rows.Count;i = i + 2)
            {
                row = table.Rows[i];
                previousRow = table.Rows[i - 1];

                foreach(string field in target.SortFields)
                {
                    DataColumn column = table.Columns[field];
                    if(column.DataType == typeof(string))
                    {
                        string value = (string)row[field];
                        string previousValue = (string)row[field];
                        int compareResult = string.Compare(previousValue, value);
                        Assert.IsTrue(compareResult <= 0);
                    }
                    else if(column.DataType == typeof(int))
                    {
                        int value = (int)row[field];
                        int previousValue = (int)row[field];
                        Assert.IsTrue(previousValue <= value);
                    }
                    //if it's not one of these two types, just let it go for now.
                }
            }
        }

        [TestMethod()]
        public void ValidFullTextSearchQueryPacket()
        {
            Search target = SearchTest.GetTestSearchObject();
            target.ApiSource = ApiSource.Service;
            target.SearchType = SearchType.FullText;
            string xml = target.BuildFullTextQueryPacket();

            XmlDocument doc = new XmlDocument();
            doc.LoadXml(xml);
        }

        [TestMethod()]
        public void ValidKeywordSearchQueryPacket()
        {
            Search target = SearchTest.GetTestSearchObject();
            target.ApiSource = ApiSource.Service;
            target.SearchType = SearchType.Keyword;
            target.DisplayFields.Add("author");
            target.DisplayFields.Add("title");
            target.SortFields.Add("author");
            target.SortFields.Add("title");
            string xml = target.BuildKeywordQueryPacket();

            XmlDocument doc = new XmlDocument();
            doc.LoadXml(xml);
        }

        [TestMethod()]
        public void TestSetFinalPacket()
        {
            Search target = SearchTest.GetTestSearchObject();
            target.ApiSource = ApiSource.Service;
            target.ContextUri = new Uri(TestSettings.ServiceUrl);
            target.Credentials = SearchTest.GetCredentials();
            target.SearchType = SearchType.Keyword;
            target.DisplayFields.Add("author");
            target.DisplayFields.Add("title");
            target.SortFields.Add("author");
            target.SortFields.Add("title");
            target.SearchText = new SearchText("test");
            string xml = target.BuildKeywordQueryPacket();

            target.Execute();

            Assert.AreEqual(xml, target.FinalQueryXml);
        }

        [TestMethod()]
        public void TestStartAndAndResultCountProperties()
        {
            Search target = new Search();
            int rowCount = int.MaxValue;
            int startAt = int.MaxValue;

            target.ResultCount = rowCount;
            target.StartAt = startAt;

            Assert.AreEqual(startAt, target.StartAt);
            Assert.AreEqual(rowCount, target.ResultCount);
        }

    }
}
